#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "GSynchronizer.h"
#include "GError.h"

namespace GThread
{

	static GWaitResult GetWaitResult(DWORD Result, GUInt32 WaitCount)
	{
		if ((WAIT_OBJECT_0 <= Result) && (Result <= (WAIT_OBJECT_0 + WaitCount - 1)))
		{
			return (GWaitResult)((GUInt32)G_WR_SIGNALED_0 + Result - WAIT_OBJECT_0);
		}
		else if ((WAIT_ABANDONED_0 <= Result) && (Result <= (WAIT_ABANDONED_0 + WaitCount - 1)))
		{
			return (GWaitResult)((GUInt32)G_WR_ABANDONED_0 + Result - WAIT_ABANDONED_0);
		}
		else if (Result == WAIT_TIMEOUT)
		{
			return G_WR_TIMEOUT;
		}

		return G_WR_SIGNALED_0;
	}

	// Description: Waits till the handle is signaled.
	// Return: Returns true is wait was successfull.
	// Notes: Handle cannot be null.
	// ----------------------------------------------------
	GWaitResult GSynch::WaitFor(const GWaitable* Waitable, GUInt32 TimeOut)
	{
		GUtil::GError::DebugCheck(Waitable == NULL, "Null parameter.");

		DWORD Result = WaitForSingleObject(Waitable->GetHandle(), TimeOut);
		if (Result == WAIT_FAILED)
		{
			GUtil::GError::Error(GUtil::GErrorMessageWin32(GetLastError()));
			return G_WR_ERROR;
		}

		return GetWaitResult(Result, 1);
	}

	// Description: Waits till the handles are signaled.
	// Return: Returns true is wait was successfull.
	// Notes: Handles cannot be null and more than 10.
	// ----------------------------------------------------
	GWaitResult GSynch::WaitFor(GWaitable* const* Waitables, GSize Count, bool WaitAll, GUInt32 TimeOut)
	{
		GUtil::GError::DebugCheck(Waitables == NULL, "Null parameter.");
		GUtil::GError::DebugCheck(Count > G_MAX_WAIT_COUNT, "Waitable object count can be maximum 10.");

		HANDLE HandleArr[G_MAX_WAIT_COUNT];

		for (GSize I = 0; I < Count; ++I)
		{
			HandleArr[I] = Waitables[I]->GetHandle();
		}

		DWORD Result = WaitForMultipleObjects((DWORD)Count, HandleArr, WaitAll, TimeOut);	
		if (Result == WAIT_FAILED)
		{
			GUtil::GError::Error(GUtil::GErrorMessageWin32(GetLastError()));
			return G_WR_ERROR;
		}

		return GetWaitResult(Result, (GUInt32)Count);
	}

};